/**
 * 通用工具模块
 */
const configure = require('@mctech/infra-configure')
const { semaphore } = require('@mctech/infra-core')
const { getSequelizeInstance } = require('../lib/sequelize')

const client = require('@mctech/infra-cloud').getRpcClient()
const userService = client.bind({ serviceId: 'user-service' })
const orgService = client.bind({ serviceId: 'org-service' })

// 获取梦诚租户信息
function getMctechTenantInfo () {
  return (
    configure.getConfig().mctechTenantInfo || {
      tenantId: 100,
      tenantCode: 'mclab'
    }
  )
}

async function getUsersMap (userIds) {
  if (userIds.length <= 0) {
    return {}
  }
  const userResults = []
  await semaphore.parallelExecute({
    input: userIds,
    batchSize: 100,
    parallelFn: async subList => {
      const subResult = await userService.get({
        path: '/users',
        query: {
          id: subList.join(',')
        }
      })
      userResults.push(...subResult)
    }
  })

  const result = userResults.reduce((userMap, user) => {
    userMap[user.userId] = user
    return userMap
  }, {})

  return result
}
/**
 * 生成 impala client bulkImport 所需的 columns 和 records
 * @param {*} sequelizeModel sequelize 模型对象
 * @param {*} dataList 数据数组
 */
function generateColsAndRecords (sequelizeModel, dataArr) {
  if (!dataArr.length) return { columns: [], records: [] }
  const rawAttributeNames = Object.keys(sequelizeModel.rawAttributes)
  const propertyNames = Object.keys(dataArr[0]).filter(i =>
    rawAttributeNames.includes(i)
  )
  const columns = propertyNames.map(i => sequelizeModel.rawAttributes[i].field)
  const records = dataArr.map(row => propertyNames.map(col => row[col]))
  return { columns, records }
}

/**
 * 批量生成插入数据
 * @param data 要插入的数据
 * @param entityModel 实体
 * @returns {{records: *, columns: *}}
 */
function generateData (data, entityModel) {
  let columns = []
  let records = []
  if (data.length) {
    const quantityRawAttributeNames = Object.keys(entityModel.rawAttributes)
    const quantityPropertyNames = Object.keys(data[0]).filter(i =>
      quantityRawAttributeNames.includes(i)
    )
    columns = quantityPropertyNames.map(i => entityModel.rawAttributes[i].field)
    records = data.map(row => quantityPropertyNames.map(col => row[col]))
  }
  return { columns, records }
}

const BATCH_SIZE = 1000
/**
 * 批量插入
 * @param entities 要插入的数据集
 * [{
 *  data, 要插入的数据 必传
 *  model, 实体类 必传
 *  batchSize, 每批的数量
 *  action 要执行de操作 inset update
 * }]
 * @returns {Promise<void>}
 */
async function bulkImport (entities) {
  if (!Array.isArray(entities) || entities.length === 0) {
    return
  }
  const sequelize = getSequelizeInstance()
  await sequelize.execute(async clients => {
    for (let i = 0; i < entities.length; i++) {
      if (!Array.isArray(entities[i].data) || entities[i].data.length === 0) {
        continue
      }
      const { records, columns } = generateData(
        entities[i].data,
        entities[i].model
      )
      await semaphore.parallelExecute({
        input: records,
        batchSize: entities[i].batchSize || BATCH_SIZE,
        parallelFn: async subList => {
          await clients.bulkImport({
            tableName: entities[i].model.tableName,
            columns: columns,
            records: subList,
            primaryKeys: ['id'],
            action: entities[i].action || 'insert'
          })
        }
      })
    }
  })
}

/**
 * 查询组织参数设置
 * @param {number} orgId 组织id
 * @param {string} bizType 参数类型
 */
async function getOrgParams (orgId, bizType) {
  return client.get(
    {
      path: `org/${orgId}/org-params`,
      query: { paramNames: bizType }
    },
    { serviceId: 'itask-service-v2' }
  )
}

/**
 * 获取月度验工周期基础设置
 * @param {number} orgId 组织id
 * @param {string} bizType 参数类型
 * @param {string} targetDate 指定日期
 */
async function getMonthDateRange (orgId, bizType, targetDate) {
  return client.get(
    {
      path: `orgs/${orgId}/month-date-range`,
      query: { bizType, targetDate }
    },
    { serviceId: 'itask-service-v2' }
  )
}

/**
 * 获取当前组织，下级的所有组织ID
 * @param {*} orgId
 * @returns {number[]}
 */
async function getChildOrg (orgId) {
  const orgs = await orgService.get({
    path: '/org-tree'
  })
  return orgs
}

module.exports = {
  getMctechTenantInfo,
  generateColsAndRecords,
  getUsersMap,
  bulkImport,
  getOrgParams,
  getMonthDateRange,
  getChildOrg
}
